#include "steelserverresponse.h"
#include "QJsonArray.h"

#include<QHttpServer>
#include <QHttpServerResponse>
#include <QJsonDocument>
#include "src/CORPattern/handleinterface.h"
#include <QCoreApplication>
#include <QFile>

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonArray>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include "src/Sock/defectdatatcpclient.h"

#include "src/Utils/defectlevelmap.h"


SteelServerResponse::SteelServerResponse(QObject *parent)
    : QObject{parent}
{


    normalDetect = new  NormalDetectBase;
    lengthDetect= new  VerticalLengthDetectBase;
    frequenceDetect= new  FrequencyDetectBase;
    directDetect= new  DirectLevelBase;
    besideDetect= new  BesideDetectBase;
    // ## 1. 启动线程和定时器
    QString jsonFlieName = "LevelForSteel.json";
    if(!jsonHelper.ReadJsonFile("LevelForSteel.json",*normalDetect,*lengthDetect,*frequenceDetect,*directDetect,*besideDetect)){
        jsonHelper.WriteJsonFile(jsonFlieName);
    }

    QString iniPath =  QCoreApplication::applicationDirPath()+ApplicationPath;
    QFile file(iniPath);
    if(file.open(QIODevice::ReadOnly)){
        InitHelper.ReadIni(iniPath);
    }else{
        InitHelper.WriteIni(iniPath);
    }
    file.close();

    timer =new QTimer(this);
    timer->setInterval(1);
    connect(timer,&QTimer::timeout,&handleseq,&TimerHandleSeq::onTimeOuthandle);
    connect(&handleseq,&TimerHandleSeq::OnSequenecChanged,this,&SteelServerResponse::getSteelInfoBySeq);

    //Tcp通信
    // tcpClient.startConnection("10.10.30.54",9086);
    // tcpClient.startConnection("127.0.0.1",9086);
    tcpClient.startConnection(IniFilehelper::tcpIp,IniFilehelper::tcpPort);
    server.route("/data", QHttpServerRequest::Method::Post, [&](const QHttpServerRequest &request) {
        QHttpServerResponse resp(QJsonDocument().toJson(),QHttpServerResponse::StatusCode::Ok);
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        resp.setHeader("Access-Control-Allow-Headers", "Content-Type");

        if(steel !=nullptr && !RequestObj.isEmpty()){

            //当前发送的数据确保是一致的
            if( RequestObj["steelName"].toString().compare(steel->getSteelName()) == 0 )
            {

                //如果上一卷的记录和当前准备发送的数据一样就不返回.
                if(LastSteel && LastSteel->getSteelName().compare(steel->getSteelName()) == 0){
                    return resp;
                }

                LastSteel =  steel ? steel : nullptr;
                QHttpServerResponse resResp(QJsonDocument(RequestObj).toJson(),QHttpServerResponse::StatusCode::Ok);
                resResp.setHeader("Access-Control-Allow-Origin", "*");
                resResp.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
                resResp.setHeader("Access-Control-Allow-Headers", "Content-Type");
                return resResp;
            }
        }
        return resp;
    });

}

void SteelServerResponse::startListen()
{
    //server.listen(QHostAddress("192.168.2.100"), 8081);
    server.listen(QHostAddress::Any, 8082);
    timer->start(1000);
}

void SteelServerResponse::getSteelInfoBySeq(int seq)
{
    //1。不存在原子操作不需要锁
    //每次更新流水号 都是新的对象和线程不会影响之前的数据
    if(timer->isActive()){
        timer->stop();
    }
    qDebug()<<"暂时关闭检测卷号,开始查询钢板信息!!!";
    steel = new SteelInfo;//钢卷信息,该数据应该持有该卷的所有数据
    steelThread = new SteelThread(seq,steel);
    connect(steelThread,&SteelThread::SteelinfoBaseChanged,this,&SteelServerResponse::getClientDefect);
    connect(steelThread,&SteelThread::finished,steelThread, &QObject::deleteLater);
    steelThread->start();


}

void SteelServerResponse::getClientDefect(int seq, SteelInfo * steel)
{
    qDebug()<<"查询缺陷信息";
    threadClient = new ClientDefectThread(seq,steel);
    connect(threadClient,&ClientDefectThread::ClientDefectFinish,this,&SteelServerResponse::getDetectSteelLevel);
    connect(threadClient,&ClientDefectThread::finished,threadClient, &QObject::deleteLater);
    threadClient->start();
}

void SteelServerResponse::getDetectSteelLevel(SteelInfo * steel)
{
    qDebug()<<"开始判断";
    //责任链
    oneHandle = new DefectOneHandle;
    twoHandle = new DefectTwoHandle;
    threeHandle = new DefectThreeHandle;

    // connect(threeHandle,&DefectThreeHandle::DetectFinish,this,&SteelServerResponse::onDetectFinish);

    connect(threeHandle,&HandleBase::DetectFinish,this,&SteelServerResponse::onDetectFinish);
    connect(twoHandle,&HandleBase::DetectFinish,this,&SteelServerResponse::onDetectFinish);
    connect(oneHandle,&HandleBase::DetectFinish,this,&SteelServerResponse::onDetectFinish);
    // oneHandle->SetNext(twoHandle)->SetNext(threeHandle);//设置链条执行顺序

    threeHandle->SetNext(twoHandle)->SetNext(oneHandle);

    threeHandle->handle(*normalDetect,*lengthDetect,*frequenceDetect,*directDetect,*besideDetect,steel);
}

void SteelServerResponse::onDetectFinish(SteelInfo *steel)
{

    RequestObj =  ParseSteelToJson(steel);

    //向数据库插入数据
    AddSteelInfo(steel);

    qDebug()<<QString("当前卷:%1检测完成,恢复卷号查询定时器").arg(steel->getSteelName());
    if(!timer->isActive()){
        timer->start();
    }
    //通信数据
    tcpClient.SendData(RequestObj);
}


int getTotalLengthByDefect(SteelInfo * steel,QString DefectName){

    //区分上下表面
    int sumLengthTop = 0;
    int sumLengthBottom = 0;
    foreach (ClientDefect * element ,steel->ClientDefect1ist) {
        if(element->getDefectName().compare(DefectName) == 0 && element->getCameraNo() <= 2){
            sumLengthTop += element->getHeight();
        }else{
            sumLengthBottom +=element->getHeight();
        }
    }
    return sumLengthTop > sumLengthBottom ? sumLengthTop : sumLengthBottom;
}

QJsonObject SteelServerResponse::ParseSteelToJson(SteelInfo *steel)
{
    QJsonObject obj;
    QJsonArray DefectArr;
    QJsonArray InfoArr;
    QJsonArray DefectNameArr;

    obj["steelName"] = steel->getSteelName();
    obj["steelNo"] = steel->getSteelNo();
    obj["steelType"] = steel->getSteelType();
    obj["length"] = steel->getLength();
    obj["thick"] = steel->getThick();
    obj["width"] = steel->getWidth();
    obj["topLen"] = steel->getTopLen();
    obj["level"] = steel->getLevel();

    foreach (auto defect, steel->ClientDefect1ist) {
        DefectArr.append(defect->toJson());
    }


    foreach (QString info, steel->infos) {
        InfoArr.append(info);
    }

    QString Reason;
    foreach (QString info, steel->infos) {
        Reason+=info;
    }
    obj["Reason"] = Reason;

    //计算上下表面的缺陷率
    foreach (QString defectName, steel->DefectNameList) {
        float defectRatioTop = 0;
        float defectBotton = 0;
        foreach (ClientDefect* ele, steel->ClientDefect1ist) {
            if(defectName.compare(ele->getDefectName())== 0 && ele->getCameraNo() <= 2 ){
                defectRatioTop+= qAbs(ele->getHeight());
            }
            else
            {
                defectBotton+= qAbs(ele->getHeight());
            }
        }
        float defectLength = defectRatioTop > defectBotton ? defectRatioTop:defectBotton;
        float defectRadio = (static_cast<float>(defectLength) / steel->getTopLen()) *100 ;
        QString defectRadioStr = QString::number(defectRadio, 'f', 1); // 保留一位
        QJsonObject element;
        element["defectName"] = defectName;
        element["defectCount"] = FindTotalCountByDefectName(defectName,steel->getSteelNo());
        element["defectRatio"] = defectRadioStr.toDouble();
        DefectNameArr.append(element);
    }

    //获取主缺陷
    int steelLv = steel->getLevel();
    QString MainDefect;
    switch (steelLv) {
    case 1:
        MainDefect = defectLevelMap.GetHighLevelDefect(steel->OneLvDefectMap.keys());
        break;
    case 2:
        MainDefect =  defectLevelMap.GetHighLevelDefect(steel->TwoLvDefectMap.keys());
        break;
    case 3:
        MainDefect = defectLevelMap.GetHighLevelDefect(steel->ThreeLvDefectMap.keys());
        break;
    }
    QJsonObject maindefectJson;
    maindefectJson["defectName"] = MainDefect;
    maindefectJson["defectCount"] = -1;
    maindefectJson["defectRatio"] = -1;
    DefectNameArr.prepend(maindefectJson);

    obj["defectList"] = DefectArr;
    obj["infoList"] = InfoArr;
    obj["defectNameList"] = DefectNameArr;
    return obj;
}

int SteelServerResponse::FindTotalCountByDefectName(QString defectName, int steelSequence)
{
    int Totalcount = 0;
    QSqlDatabase db = dbhelper.openDataBase("conn_findCount","SteelRecord");

    for (int i = 1; i < IniFilehelper::camNum; ++i) {
        QString str = R"(
        use [ClientDefectDB%1]
        select COUNT(defectClass.Name) as TotalCount
        from
        [dbo].[Defect] as defect,
        [ConfigCenter].[dbo].[DefectClass] as defectClass
        where defect.Class = defectClass.Class and
        defect.SteelNo = %2
        and defectClass.Name = '%3'
        )";
        QString Sqlstr =  str.arg(i).arg(steelSequence).arg(defectName);
        QSqlQuery query(db);
        query.exec(Sqlstr);
        while(query.next()){
            Totalcount += query.record().value("TotalCount").toInt();
        }
    }
    db.close();
    return Totalcount;
}

void SteelServerResponse::AddSteelInfo(SteelInfo *steel)
{
    if(steel->getSteelName().isEmpty() ){
        return;
    }
    QSqlDatabase db = dbhelper.openDataBase("conn_AddSteelInfo","SteelDetectLv");
    //查询是否存在
    QString selectStr = R"(
    Use SteelDetectLv
    select * from [dbo].[SteelGradeInfo] where [SteelName] = :steelName ;
    )";

    QSqlQuery query(db);
    query.prepare(selectStr);
    query.bindValue(":steelName",steel->getSteelName());

    if(query.exec() && query.next()){
        qDebug() << "记录已存在,不在重复插入数据!";
        db.close();
        return;
    }

    //将多个降级的原因拼接通过,分隔
    QString concatenatedString =  steel->infos.join(",");

    //不存在就进行插入
    QString insertStr = R"(
        Use SteelDetectLv
        Insert into [dbo].[SteelGradeInfo]([Sequence],[SteelName],[DetectTime],[SteelType],[Grade],[Dsc])
        VALUES (:sequence, :sName, GETDATE(), :steelType, :grade, :Dsc);
    )";



    query.prepare(insertStr);
    query.bindValue(":sequence",steel->getSteelNo());
    query.bindValue(":sName",steel->getSteelName());
    query.bindValue(":steelType",steel->getSteelType());
    query.bindValue(":grade",steel->getLevel());
    query.bindValue(":Dsc",concatenatedString);


    if(!query.exec()){
          qDebug() << "Failed to insert data:" << query.lastError().text();
    }

    db.close();

}




